﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ComicTool.Drawing;
using ImageTools;
using SharpCompress.Archive;

namespace ComicTool.Model
{
    public class Page : ViewModelBase, IComparable<Page>
    {
        private IArchiveEntry entry;
        public Page(IArchiveEntry entry)
        {
            this.entry = entry;
            Paths = new List<DrawingItem>();
        }

        private ExtendedImage image;
        public ExtendedImage Image
        {
            get
            {
                if ((image == null) && (!IsLoaded))
                {
                    ExtractIfRequired();
                    WriteableBitmap wb = CreateImage(new MemoryStream(Bytes), null);
                    if (wb != null)
                    {
                        image = wb.ToImage();
                    }
                    IsLoaded = true;
                }
                return image;
            }
        }

        private WriteableBitmap thumbnail;
        public WriteableBitmap Thumbnail
        {
            get
            {
                ExtractIfRequired();
                if ((thumbnail == null) && (Bytes != null))
                {
                    thumbnail = CreateImage(new MemoryStream(Bytes), 90);
                }
                return thumbnail;
            }

        }

        public List<DrawingItem> Paths
        {
            get;
            private set;
        }

        private bool isLoaded;
        public bool IsLoaded
        {
            get
            {
                return isLoaded;
            }
            private set
            {
                isLoaded = value;
                OnPropertyChanged("IsLoaded");
                OnPropertyChanged("Paths");
            }
        }

        internal void ExtractIfRequired()
        {
            if (Bytes == null)
            {
                Bytes = ExtractBytes();
            }
        }

        private WriteableBitmap CreateImage(Stream stream, int? height)
        {
            try
            {
                BitmapImage bi = new BitmapImage();
                bi.SetSource(stream);

                double cy = height ?? bi.PixelHeight;
                double cx = bi.PixelWidth * (cy / bi.PixelHeight);

                Image image = new Image();
                image.Source = bi;

                WriteableBitmap wb1 = new WriteableBitmap((int)cx, (int)cy);
                ScaleTransform transform = new ScaleTransform();
                transform.ScaleX = cx / bi.PixelWidth;
                transform.ScaleY = cy / bi.PixelHeight;
                wb1.Render(image, transform);
                wb1.Invalidate();

                WriteableBitmap wb2 = new WriteableBitmap((int)cx, (int)cy);
                for (int i = 0; i < wb2.Pixels.Length; i++)
                    wb2.Pixels[i] = wb1.Pixels[i];
                wb2.Invalidate();

                return wb2;
            }
            catch (Exception e)
            {
                Exception = e.ToString();
                OnPropertyChanged("ToolTip");
                HasError = true;
                return null;
            }
        }

        internal void RefreshImage()
        {
            OnPropertyChanged("Image");
            OnPropertyChanged("IsLoaded");
            OnPropertyChanged("Thumbnail");
        }

        public byte[] Bytes
        {
            get;
            private set;
        }

        public int CompareTo(Page other)
        {
            return Name.CompareTo(other.Name);
        }

        public bool HasError
        {
            get;
            private set;
        }

        public string ToolTip
        {
            get
            {
                if (Exception.IsNullOrEmpty())
                {
                    return Name;
                }
                else
                {
                    return Name + Environment.NewLine + Exception;
                }
            }
        }

        private string Exception
        {
            get;
            set;
        }
        public string Name
        {
            get
            {
                return entry.FilePath;
            }
        }
        public byte[] ExtractBytes()
        {
            MemoryStream output = new MemoryStream();
            entry.WriteTo(output);
            output.Position = 0;
            return output.ToArray();
        }
    }
}
